package com.snmp.test.snmp;


import com.alibaba.fastjson.JSONObject;
import com.snmp.test.config.AppConfigRead;
import com.snmp.test.entity.WirelessAlarmData;
import com.snmp.test.utils.SnmpTrapFilter;
import com.snmp.test.utils.StringTansUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.*;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Vector;

@Component
public class MultiThreadedTrapReceiver implements CommandResponder {
    /**
     * 接收SNMP TRAP 报文
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(MultiThreadedTrapReceiver.class);
    @Autowired
    private AppConfigRead appConfigRead;
    private MultiThreadedMessageDispatcher dispatcher;
    private Snmp snmp = null;
    private Address listenAddress;
    private ThreadPool threadPool;
    private SimpleDateFormat simpleDateFormat;


    public MultiThreadedTrapReceiver() {
        // BasicConfigurator.configure();
        simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }

    private void init() throws UnknownHostException, IOException {
        threadPool = ThreadPool.create("Trap", 2);
        dispatcher = new MultiThreadedMessageDispatcher(threadPool,
                new MessageDispatcherImpl());
        listenAddress = GenericAddress.parse(System.getProperty(
                "snmp4j.listenAddress", "udp:" + appConfigRead.getListenAddress())); // 本地IP与监听端口
        TransportMapping transport;
        // 对TCP与UDP协议进行处理
        if (listenAddress instanceof UdpAddress) {
            transport = new DefaultUdpTransportMapping((UdpAddress) listenAddress);
            LOGGER.info("使用UDP协议");
        } else {
            transport = new DefaultTcpTransportMapping(
                    (TcpAddress) listenAddress);
            LOGGER.info("使用TCP协议");
        }
        snmp = new Snmp(dispatcher, transport);
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3());
        USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3
                .createLocalEngineID()), 0);
        SecurityModels.getInstance().addSecurityModel(usm);
        snmp.listen();
    }


    public void run() {
        try {
            init();
            snmp.addCommandResponder(this);
            LOGGER.info("开始监听Trap信息");
            //  System.out.println("开始监听Trap信息!");
        } catch (Exception ex) {
            LOGGER.error("监听异常");
            ex.printStackTrace();

        }
    }

    /**
     * 实现CommandResponder的processPdu方法, 用于处理传入的请求、PDU等信息
     * 当接收到trap时，会自动进入这个方法
     *
     * @param respEvnt
     */
    @Override
    public void processPdu(CommandResponderEvent respEvnt) {
        // 解析Response
        if (respEvnt != null && respEvnt.getPDU() != null) {
            Map<String, String> oidToString = SnmpTrapFilter.snmpTrapMapping();
            Vector<? extends VariableBinding> recVBs = (Vector<? extends VariableBinding>) respEvnt.getPDU().getVariableBindings();
            JSONObject jsonObject = new JSONObject();
            for (int i = 0; i < recVBs.size(); i++) {
                VariableBinding recVB = recVBs.elementAt(i);
                String oid = recVB.getOid().toString();
                String variable = recVB.getVariable().toString();
                //LOGGER.info(recVB.getOid() + " : " + recVB.getVariable());
                // 将hex 编码转换成中文
                if (SnmpTrapFilter.filerHexString(variable)) {
                    variable = StringTansUtil.hexStr2Str(variable.replaceAll(":", ""));
                }
                jsonObject.put(oidToString.get(oid), variable);
                //生成告警ID
                Date date = new Date();
                String alarmNEDevID = jsonObject.getString("AlarmNEDevID");           //设备唯一标识(网元名称)
                String alarmSpecificproblems = jsonObject.getString("AlarmSpecificproblems");  //告警详细原因
                String alarmId = getHashCode(alarmNEDevID + alarmSpecificproblems) + "_" + date.getTime();
                jsonObject.put("alarmId", alarmId);
            }

            LOGGER.info(jsonObject.toJSONString());

            //持久化无线专网告警数据
            WirelessAlarmData record = new WirelessAlarmData();
            record.setAckTime(jsonObject.getString("AlarmAckTime"));
            record.setAdditionalInfo(jsonObject.getString("AlarmAdditionalInfo"));
            record.setAlarmCategory(jsonObject.getString("AlarmCategory"));
            record.setAlarmConfirm(jsonObject.getIntValue("AlarmConfirm"));
            record.setAlarmCsn(jsonObject.getString("AlarmCsn"));
            record.setAlarmLevel(jsonObject.getIntValue("AlarmLevel"));
            record.setAlarmOperator(jsonObject.getString("AlarmOperator"));
            record.setAlarmProbablecause(jsonObject.getString("AlarmProbablecause"));
            record.setAlarmProposedrepairactions(jsonObject.getString("AlarmProposedrepairactions"));
            record.setAlarmRestore(jsonObject.getInteger("AlarmRestore"));
            record.setAlarmSpecificproblems(jsonObject.getString("AlarmSpecificproblems"));
            record.setAlarmType(jsonObject.getInteger("AlarmType"));
            record.setAlId(jsonObject.getString("AlId"));
            record.setClearCategory(jsonObject.getString("AlarmClearCategory"));
            record.setClearOperator(jsonObject.getString("AlarmClearOperator"));
            record.setClearType(jsonObject.getString("AlarmClearType"));
            record.setDevCsn(jsonObject.getString("AlarmDevCsn"));
            record.setExtendInfo(jsonObject.getString("AlarmExtendInfo"));
            record.setMoName(jsonObject.getString("AlarmMoName"));
            record.setNeDevId(jsonObject.getString("AlarmNeDevId"));
            record.setNeIpAddr(jsonObject.getString("AlarmNeIpAddr"));
            record.setNeType(jsonObject.getString("AlarmNeType"));
            record.setObjectInstanceType(jsonObject.getString("AlarmObjectInstanceType"));
            record.setOccurTime(jsonObject.getString("AlarmOccurTime"));
            record.setProductId(jsonObject.getInteger("ProductId"));
            record.setRestoreTime(jsonObject.getString("AlarmRestoreTime"));
            record.setServiceAffectFlag(jsonObject.getString("AlarmServiceAffectFlag"));
            record.setAlarmProbablecause(jsonObject.getString("AlarmProbablecause"));

            LOGGER.info("获得无线专网告警数据结果：" + record);

        }
    }

    /**
     * 获取哈希值（正数）
     *
     * @param str
     * @return
     */
    public static int getHashCode(String str) {
        return Math.abs((str + "wireless").hashCode());
    }

    public static void main(String[] args) {
        MultiThreadedTrapReceiver multithreadedtrapreceiver = new MultiThreadedTrapReceiver();
        multithreadedtrapreceiver.run();
    }
}

